Processing Data with the objetive of designing metrics for team performance - Open17 Climate Gender

  1. Read the data files

library(readxl)
library(tidyr)
library(dplyr)
library(ggplot2)
library(plotly)

source("../../Accelerate/notebooks/custom_functions.R")

teams = read_excel("../data/O17ClimateGender_teamformation.xlsx")
#teams = lapply(teams, as.character)

assesment = read_excel("../data/O17ClimateGender_assessment.xlsx")

load("../../Accelerate/processed data/registration.RData")

map = read.csv("../../Accelerate/data/team_users_hashed.csv", stringsAsFactors = FALSE)
colnames(map) = c("Team", "ID", "Hash", "Mentors")

reg = merge(reg, map[,c("Team", "Hash")], by.x = "ID", by.y = "Hash")

reg_map = c("A2: Women & Technology Against Climate Change" = "T6: Women & Technology Against Climate Change", "B2: TEAM FOILED" = "T3: TEAM FOILED", "C1: Andapé Institute" = "T13: Andapé Institute", "C3: WOMER" = "T5: WOMER", "A5: Donate Water Project" = "T9: DonateWater", "B5: Rights of Climate" = "T11: Rights of Climate", "B3: Eco Winners" = "T14: Eco Winners", "B4: Women 4 Sustainable World" = "T12: Women 4 Sustainable World", "A1: Up Get App/CitiCERN" = "T7: UpGet app - CitiCERN Project", "B1: Water Warriors" = "T10: Water Warriors", "C2: PAM" = "T4: PAM", "C4: Climate Gender Justice" = "T8: Climate Gender Justice", "A3: Rhythm of Bamboos" = "T1: SDesiGn (Old name: Rhythm of Bamboos)", "C5: Ashifa Nazrin" = "C5: Ashifa Nazrin", "A4: Flood Rangers" = "T2: Flood Rangers")

reg_map = data.frame(old_name = names(reg_map), new_name = reg_map)
reg = merge(reg, reg_map, by.x = "Team", by.y = "old_name", all.x = TRUE)

write.csv(unnest(reg, cols = c("communication")), file = "../processed data/reg_edited.csv")

map = merge(map, reg_map, by.x = "Team", by.y = "old_name", all.x = TRUE)
map$new_name = as.character(map$new_name)
map$new_name[map$Team == "Organizing Team"] = "Organizing Team"

Outcome Variable

  1. Outcome end of Evaluate

outcome = assesment[,c("Team", "Total", "Weekly Evaluation", "Commitment", "Attendance", "Deliverables")]
outcome = merge(outcome, teams[,c("Team Name", "Stage")], by.x = "Team", by.y = "Team Name", all.x = TRUE)
outcome$Stage = factor(outcome$Stage, levels = c("Evaluate", "Accelerate", "Refine"), ordered = TRUE)
  1. Surveys and Interactions

load("../../Evaluate/processed data/surveys.RData")

inter = interactions[,c(1,8,2,3)]
inter = merge(inter, map[,c("ID", "new_name")], by.x = "user_id", by.y = "ID", all.x = TRUE)
colnames(inter) = c("From", "To", "Survey_id", "Question", "From_team")
inter = merge(inter, map[,c("ID", "new_name")], by.x = "To", by.y = "ID", all.x = TRUE)
colnames(inter)[colnames(inter) == "new_name"] = "To_team"

inter = inter[!inter$To %in% c(34), c(2,1,3,4,5,6)]

g_int_teams = graph_from_data_frame(inter[,c(5,6,1:4)], directed = TRUE, vertices = teams)
E(g_int_teams)$weight = 1
g_int_teams_simp = simplify(g_int_teams, remove.loops = FALSE)
  1. Create an Extensive dataframe with different things that can be calculated with the Interaction data

Listing them out here (by Team)

  1. of responses

  2. in-degree (self, from other teams) + normalised (proportion of in edges to self/others etc.)
  3. out-degree (org team, other teams) + normalised
  4. …

inter_pr = inter %>% group_by(From_team, To_team) %>% summarise(weight = n())
`summarise()` has grouped output by 'From_team'. You can override using the `.groups` argument.
# Responses, Out degree to Org Team, Other peers, Self

temp = inter_pr %>% group_by(From_team) %>% summarise(no_responses = n(), self_interactions = weight[To_team == From_team], org_interactions = weight[To_team == "Organizing Team"], peers_out = sum(weight[!To_team %in% c(From_team, "Organizing Team")]))

stats = temp

# In-degree from other peers

temp = inter_pr %>% group_by(To_team) %>% summarise(peers_in = sum(weight[!From_team %in% c(To_team, "Organizing Team")]))
stats = merge(stats, temp, by.x = "From_team", by.y = "To_team", all.x = TRUE, all.y = TRUE)

stats$self_interactions_norm = 2*stats$self_interactions/(2*stats$self_interactions + stats$peers_in + stats$org_interactions + stats$peers_out)
stats$org_interactions_norm = stats$org_interactions/(2*stats$self_interactions + stats$peers_in + stats$org_interactions + stats$peers_out)
stats$peers_out_norm = stats$peers_out/(2*stats$self_interactions + stats$peers_in + stats$org_interactions + stats$peers_out)
stats$peers_in_norm = stats$peers_in/(2*stats$self_interactions + stats$peers_in + stats$org_interactions + stats$peers_out)

stats = stats[!stats$From_team %in% c("Organizing Team"),]

Slack Interactions


load("../../Evaluate/processed data/slack_all_int.RData")

inter_sl = df_total %>% group_by(From_Team, To_Team) %>% summarise(weight = n())
`summarise()` has grouped output by 'From_Team'. You can override using the `.groups` argument.
colnames(inter_sl) = c("From_team", "To_team", "weight")

temp_1 = inter_sl %>% group_by(From_team) %>% summarise(slack_self_interactions = weight[To_team == From_team], slack_org_out = weight[To_team == "Organizing Team"], slack_peers_out = sum(weight[!To_team %in% c(From_team, "Organizing Team")]))
`summarise()` has grouped output by 'From_team'. You can override using the `.groups` argument.
temp_2 = inter_sl %>% group_by(To_team) %>% summarise(slack_peers_in = sum(weight[!From_team %in% c(To_team, "Organizing Team")]), slack_org_in = weight[From_team == "Organizing Team"])

slack_stats = merge(temp_1, temp_2, by.x = "From_team", by.y = "To_team", all.x = TRUE, all.y = TRUE)
slack_stats = slack_stats[!slack_stats$From_team %in% c("Organizing Team", "Tool Owner"),]

slack_stats = merge(slack_stats, reg_map, by.x = "From_team", by.y = "old_name", all.x = TRUE)
slack_stats$From_team = slack_stats$new_name
slack_stats = slack_stats %>% select(-new_name)
slack_stats[is.na(slack_stats)] = 0


slack_stats$slack_self_interactions_norm = 2*slack_stats$slack_self_interactions/(2*slack_stats$slack_self_interactions + slack_stats$slack_org_out + slack_stats$slack_peers_out + slack_stats$slack_peers_in + slack_stats$slack_org_in)

slack_stats$slack_org_out_norm = slack_stats$slack_org_out/(2*slack_stats$slack_self_interactions + slack_stats$slack_org_out + slack_stats$slack_peers_out + slack_stats$slack_peers_in + slack_stats$slack_org_in)
slack_stats$slack_peers_out_norm = slack_stats$slack_peers_out/(2*slack_stats$slack_self_interactions + slack_stats$slack_org_out + slack_stats$slack_peers_out + slack_stats$slack_peers_in + slack_stats$slack_org_in)
slack_stats$slack_peers_in_norm = slack_stats$slack_peers_in/(2*slack_stats$slack_self_interactions + slack_stats$slack_org_out + slack_stats$slack_peers_out + slack_stats$slack_peers_in + slack_stats$slack_org_in)
slack_stats$slack_org_in_norm = slack_stats$slack_org_in/(2*slack_stats$slack_self_interactions + slack_stats$slack_org_out + slack_stats$slack_peers_out + slack_stats$slack_peers_in + slack_stats$slack_org_in)

Merge


interaction_stats = merge(stats, slack_stats, by.x = "From_team", by.y = "From_team", all.x = TRUE, all.y = TRUE)

Network Properties


network_stats = data.frame(nodes = V(g_int_teams_simp)$name, strength_in = strength(g_int_teams_simp, mode = "in"), strength_out = strength(g_int_teams_simp, mode = "out"), betweenness = betweenness(g_int_teams_simp, weights = 1/E(g_int_teams_simp)$weight, normalized = TRUE), burt = constraint(g_int_teams_simp, weights = E(g_int_teams_simp)$weight))

  1. Thinking about Metrics
  1. Descriptive
  1. Gender Diversity
  2. Assembled/Self organised
  3. Background
  4. SDG experience
  1. Interactions
  1. Interaction with ORG
  2. Interaction with Team members
  3. Interaction with other teams
  1. Tasks

  1. Processing Reg. file to make teamwise diversity metrics

Entropy - low score for less diversity (Higher for more diversity)


shannon = function(list)
{
  ent = 0
  for (i in unique(list))
  {
    t = sum(list == i)
    n = length(list)
    ent = ent + (t/n)*log(t/n)
  }
  
  return(-1*ent)
}

simpson = function(list)
{
  ent = 0
  for (i in unique(list))
  {
    t = sum(list == i)
    n = length(list)
    ent = ent + (t/n)*(t/n)
  }
  
  return(1/ent)
}

metrics = data.frame(Team = unique(reg$new_name))

for (i in c("gender", "country_orig", "country_resid", "education", "communication", "exante_project_SDG", "background", "occupation"))
{
  temp = reg[,c("new_name", i)]
  temp = clean_split_mcq(temp)
  colnames(temp) = c("Team", "var")
  
#  num = temp$var
  
  t = temp %>% group_by(Team) %>% summarise(shannon = shannon(var), simpson = simpson(var))
  colnames(t) = c("Team", paste(i, "_shannon", sep = ''), paste(i, "_simpson", sep = ''))
  
  metrics = merge(metrics, t, by.x = "Team", by.y = "Team", all.x = TRUE, all.y = TRUE)
  
}

metrics = merge(metrics, teams, by.x = "Team", by.y = "Team Name", all.x = TRUE)

metrics_score = merge(metrics, assesment, by.x = "Team", by.y = "Team", all.x = TRUE, all.y = TRUE)

library(corrplot)

#metrics_score$`Final Pitch` = as.numeric(metrics_score$`Final Pitch`)
#M = cor(metrics_score[,c(2,4,6,8,10,14,16,19,21,24:27,31)], use = "complete.obs")
#corrplot(M, method = 'number') # colorful number

temp = merge(interaction_stats, outcome, by.x = "From_team", by.y = "Team", all.x = TRUE, all.y = TRUE)
M = cor(temp[,c(2:(ncol(temp)-1))], use = "complete.obs")
corrplot(M, method = "number")

Cleaner Version


outcome = c("Final Pitch", "Appropriateness of Methodology", "Weekly Evaluation", "Commitment", "Attendance", "Deliverables", "Sum", "Total")

df_corr = data.frame()

for (i in outcome)
{
  for (j in colnames(interaction_stats))
  {
    if(!j %in% c("From_team", "no_responses"))
    {
      c = cor.test(temp[,j], temp[,i])
      
      df_corr = rbind(df_corr, data.frame(i = i, j = j, cor = c$estimate, p_val = c$p.value))
      
    }
  }
}

df_corr$cor[df_corr$p_val > 0.1] = 0
df_corr$cor = round(df_corr$cor, 3)

plt = ggplot(df_corr) + geom_tile(aes(x = i, y = j, fill = cor), lwd = 1.5, linetype = 1) + scale_fill_gradient2(low = "blue", high = "red") + theme_bw() + theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(), panel.background = element_blank()) + ylab("") + xlab("") + geom_text(aes(x = i, y = j, label = cor))

ggplotly(plt)

Network Props


temp = merge(assesment, network_stats, by.x = "Team", by.y = "nodes", all.x = TRUE, all.y = TRUE)
temp = temp[!temp$Team == "Organizing Team",]

outcome = c("Final Pitch", "Appropriateness of Methodology", "Weekly Evaluation", "Commitment", "Attendance", "Deliverables", "Sum", "Total")

df_corr = data.frame()

for (i in outcome)
{
  for (j in colnames(network_stats))
  {
    if(!j %in% c("nodes"))
    {
      c = cor.test(temp[,j], temp[,i])
      
      df_corr = rbind(df_corr, data.frame(i = i, j = j, cor = c$estimate, p_val = c$p.value))
      
    }
  }
}


df_corr$cor[df_corr$p_val > 0.1] = 0
df_corr$cor = round(df_corr$cor, 3)

plt = ggplot(df_corr) + geom_tile(aes(x = i, y = j, fill = cor), lwd = 1.5, linetype = 1) + scale_fill_gradient2(low = "blue", high = "red") + theme_bw() + theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(), panel.background = element_blank()) + ylab("") + xlab("") + geom_text(aes(x = i, y = j, label = cor))

ggplotly(plt)

Diversity


inter = interactions[,c(1,8,2,3)]
inter = merge(inter, map[,c("ID", "Team")], by.x = "user_id", by.y = "ID", all.x = TRUE)
colnames(inter) = c("From", "To", "Survey_id", "Question", "From_team")
inter = merge(inter, map[,c("ID", "Team")], by.x = "To", by.y = "ID", all.x = TRUE)
colnames(inter)[colnames(inter) == "Team"] = "To_team"

inter = inter[!inter$To %in% c(34), c(2,1,3,4,5,6)]

g_int_teams = graph_from_data_frame(inter[,c(5,6,1:4)], directed = TRUE)
E(g_int_teams)$weight = 1
g_int_teams_simp = simplify(g_int_teams, remove.loops = FALSE)

Some Teamwise Network Properties


inter = interactions[,c(1,8,2,3)]
inter = merge(inter, map[,c("ID", "Team")], by.x = "user_id", by.y = "ID", all.x = TRUE)
colnames(inter) = c("From", "To", "Survey_id", "Question", "From_team")
inter = merge(inter, map[,c("ID", "Team")], by.x = "To", by.y = "ID", all.x = TRUE)
colnames(inter)[colnames(inter) == "Team"] = "To_team"

inter = inter[!inter$To %in% c(34), c(2,1,3,4,5,6)]

g_int_teams = graph_from_data_frame(inter[,c(5,6,1:4)], directed = TRUE)
E(g_int_teams)$weight = 1
g_int_teams_simp = simplify(g_int_teams, remove.loops = FALSE)

Network Metrics

  1. Weighted interactions (Other teams, self, ORG)
  2. Normalised weighted interactions - total = 1

process_interactions = function(inter)
{
  temp = inter %>% group_by(From_team, To_team) %>% summarise(weight = n())
  temp_out = temp %>% group_by(From_team) %>% summarise(self = weight[To_team == From_team], org_out = weight[To_team == "Organizing Team"], peers_out = sum(weight[!To_team %in% c(From_team, "Organizing Team")]))

  temp_in = temp %>% group_by(To_team) %>% summarise(peers_in = sum(weight[!From_team == To_team]))

  degr = merge(temp_out, temp_in, by.x = "From_team", by.y = "To_team", all.x = TRUE, all.y = TRUE)
  colnames(degr)[colnames(degr) == "From_team"] = "Team"

  degr = degr[!degr$Team == "Organizing Team",]
  return(degr)
}
pdf("../figures/stats_team_type_box.pdf")

for (i in colnames(degr_as))
{
  if(!i %in% c("new_name", "Team", "Type", "Geographic Location", "Gender F/M", "Stage"))
  {
    temp = degr_as[,c("Type", i)]
    colnames(temp) = c("Type", "var")
    #t = temp %>% group_by(Type) %>% summarise(mean = mean(var), se = se(var))
    
    plt = ggplot(temp, aes(x = Type, y = var)) + geom_boxplot() + theme_bw(base_size = 20) + xlab("") + ylab("") + ggtitle(i) + geom_point(aes(x = Type, y = var), alpha = 0.3)
    
    print(plt)
    
  }
}
Warning: Removed 8 rows containing non-finite values (stat_boxplot).
Warning: Removed 8 rows containing missing values (geom_point).
Warning: Removed 4 rows containing non-finite values (stat_boxplot).
Warning: Removed 4 rows containing missing values (geom_point).
dev.off()
null device 
          1 

Pre-Formed vs Assembled

  1. All Interactions


for (j in unique(inter$Question))
{  
  
  a = process_interactions(inter[inter$Question == j,])
  a = merge(a, reg_map, by.x = "Team", by.y = "old_name")
  a = merge(a, teams, by.x = "new_name", by.y = "Team Name")
  
  pdf(paste("../figures/", j, "_box.pdf", sep = ""))
  
  for (i in colnames(a))
  {
    if(!i %in% c("new_name", "Team", "Type", "Stage"))
    {
      temp = a[,c("Type", i)]
      colnames(temp) = c("Type", "var")
      plt = ggplot(temp, aes(x = Type, y = var)) + geom_boxplot() + theme_bw(base_size = 20) + xlab("") + ylab("") + ggtitle(i) + geom_point(aes(x = Type, y = var), alpha = 0.3)
      
      print(plt)
      
    }
  }
  
  dev.off()
  
pdf(paste("../figures/", j, "_bar.pdf", sep = ""))

for (i in colnames(a))
{
  if(!i %in% c("new_name", "Team", "Type", "Geographic Location", "Gender F/M", "Stage"))
  {
    temp = a[,c("Type", i)]
    colnames(temp) = c("Type", "var")
    t = temp %>% group_by(Type) %>% summarise(mean = mean(var), se = se(var))
    
    plt = ggplot(t, aes(x = Type, y = mean)) + geom_bar(stat = "identity") + geom_errorbar(aes(ymin = mean-se, ymax = mean+se), width = 0) + theme_bw(base_size = 20) + xlab("") + ylab("") + ggtitle(i)
    
    print(plt)
    
  }
}

dev.off()

}
`summarise()` has grouped output by 'From_team'. You can override using the `.groups` argument.
`summarise()` has grouped output by 'From_team'. You can override using the `.groups` argument.
Warning: Removed 13 rows containing non-finite values (stat_boxplot).
Warning: Removed 13 rows containing missing values (geom_point).
Warning: Removed 13 rows containing non-finite values (stat_boxplot).
Warning: Removed 13 rows containing missing values (geom_point).
Warning: Removed 13 rows containing non-finite values (stat_boxplot).
Warning: Removed 13 rows containing missing values (geom_point).
Warning: Removed 2 rows containing missing values (position_stack).
Warning: Removed 2 rows containing missing values (position_stack).
Warning: Removed 2 rows containing missing values (position_stack).
`summarise()` has grouped output by 'From_team'. You can override using the `.groups` argument.
`summarise()` has grouped output by 'From_team'. You can override using the `.groups` argument.
`summarise()` has grouped output by 'From_team'. You can override using the `.groups` argument.
`summarise()` has grouped output by 'From_team'. You can override using the `.groups` argument.
Warning: Removed 3 rows containing non-finite values (stat_boxplot).
Warning: Removed 3 rows containing missing values (geom_point).
Warning: Removed 3 rows containing non-finite values (stat_boxplot).
Warning: Removed 3 rows containing missing values (geom_point).
Warning: Removed 3 rows containing non-finite values (stat_boxplot).
Warning: Removed 3 rows containing missing values (geom_point).
Warning: Removed 1 rows containing missing values (position_stack).
Warning: Removed 1 rows containing missing values (position_stack).
Warning: Removed 1 rows containing missing values (position_stack).
  1. Specific Interactions

pdf("../figures/stats_team_progress_box.pdf")

for (i in colnames(degr_as))
{
  if(!i %in% c("new_name", "Team", "Type", "Geographic Location", "Gender F/M", "Stage"))
  {
    temp = degr_as[,c("Stage", i)]
    colnames(temp) = c("Type", "var")
    #t = temp %>% group_by(Type) %>% summarise(mean = mean(var), se = se(var))
    
    plt = ggplot(temp, aes(x = Type, y = var)) + geom_boxplot() + theme_bw(base_size = 20) + xlab("") + ylab("") + ggtitle(i) + geom_point(aes(x = Type, y = var), alpha = 0.3)
    
    print(plt)
    
  }
}
Warning: Removed 8 rows containing non-finite values (stat_boxplot).
Warning: Removed 8 rows containing missing values (geom_point).
Warning: Removed 4 rows containing non-finite values (stat_boxplot).
Warning: Removed 4 rows containing missing values (geom_point).
dev.off()
null device 
          1 
pdf("../figures/stats_team_progress_bar.pdf")

for (i in colnames(degr_as))
{
  if(!i %in% c("new_name", "Team", "Type", "Geographic Location", "Gender F/M", "Stage"))
  {
    temp = degr_as[,c("Stage", i)]
    colnames(temp) = c("Type", "var")
    t = temp %>% group_by(Type) %>% summarise(mean = mean(var), se = se(var))
    
    plt = ggplot(t, aes(x = Type, y = mean)) + geom_bar(stat = "identity") + geom_errorbar(aes(ymin = mean-se, ymax = mean+se), width = 0) + theme_bw(base_size = 20) + xlab("") + ylab("") + ggtitle(i)
    
    print(plt)
    
  }
}
Warning: Removed 1 rows containing missing values (position_stack).
Warning: Removed 1 rows containing missing values (position_stack).
dev.off()
null device 
          1 


pdf("../figures/stats_team_progress_box.pdf")

for (i in colnames(degr_as))
{
  if(!i %in% c("new_name", "Team", "Type", "Geographic Location", "Gender F/M", "Stage"))
  {
    temp = degr_as[,c("Stage", i)]
    colnames(temp) = c("Type", "var")
    #t = temp %>% group_by(Type) %>% summarise(mean = mean(var), se = se(var))
    
    plt = ggplot(temp, aes(x = Type, y = var)) + geom_boxplot() + theme_bw(base_size = 20) + xlab("") + ylab("") + ggtitle(i) + geom_point(aes(x = Type, y = var), alpha = 0.3)
    
    print(plt)
    
  }
}

dev.off()


pdf("../figures/stats_team_progress_bar.pdf")

for (i in colnames(degr_as))
{
  if(!i %in% c("new_name", "Team", "Type", "Geographic Location", "Gender F/M", "Stage"))
  {
    temp = degr_as[,c("Stage", i)]
    colnames(temp) = c("Type", "var")
    t = temp %>% group_by(Type) %>% summarise(mean = mean(var), se = se(var))
    
    plt = ggplot(t, aes(x = Type, y = mean)) + geom_bar(stat = "identity") + geom_errorbar(aes(ymin = mean-se, ymax = mean+se), width = 0) + theme_bw(base_size = 20) + xlab("") + ylab("") + ggtitle(i)
    
    print(plt)
    
  }
}

dev.off()
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKUHJvY2Vzc2luZyBEYXRhIHdpdGggdGhlIG9iamV0aXZlIG9mIGRlc2lnbmluZyBtZXRyaWNzIGZvciB0ZWFtIHBlcmZvcm1hbmNlIC0gT3BlbjE3IENsaW1hdGUgR2VuZGVyCgoKMS4gUmVhZCB0aGUgZGF0YSBmaWxlcwoKYGBge3J9CgpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeSh0aWR5cikKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBsb3RseSkKCnNvdXJjZSgiLi4vLi4vQWNjZWxlcmF0ZS9ub3RlYm9va3MvY3VzdG9tX2Z1bmN0aW9ucy5SIikKCnRlYW1zID0gcmVhZF9leGNlbCgiLi4vZGF0YS9PMTdDbGltYXRlR2VuZGVyX3RlYW1mb3JtYXRpb24ueGxzeCIpCiN0ZWFtcyA9IGxhcHBseSh0ZWFtcywgYXMuY2hhcmFjdGVyKQoKYXNzZXNtZW50ID0gcmVhZF9leGNlbCgiLi4vZGF0YS9PMTdDbGltYXRlR2VuZGVyX2Fzc2Vzc21lbnQueGxzeCIpCgpsb2FkKCIuLi8uLi9BY2NlbGVyYXRlL3Byb2Nlc3NlZCBkYXRhL3JlZ2lzdHJhdGlvbi5SRGF0YSIpCgptYXAgPSByZWFkLmNzdigiLi4vLi4vQWNjZWxlcmF0ZS9kYXRhL3RlYW1fdXNlcnNfaGFzaGVkLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKY29sbmFtZXMobWFwKSA9IGMoIlRlYW0iLCAiSUQiLCAiSGFzaCIsICJNZW50b3JzIikKCnJlZyA9IG1lcmdlKHJlZywgbWFwWyxjKCJUZWFtIiwgIkhhc2giKV0sIGJ5LnggPSAiSUQiLCBieS55ID0gIkhhc2giKQoKcmVnX21hcCA9IGMoIkEyOiBXb21lbiAmIFRlY2hub2xvZ3kgQWdhaW5zdCBDbGltYXRlIENoYW5nZSIgPSAiVDY6IFdvbWVuICYgVGVjaG5vbG9neSBBZ2FpbnN0IENsaW1hdGUgQ2hhbmdlIiwgIkIyOiBURUFNIEZPSUxFRCIgPSAiVDM6IFRFQU0gRk9JTEVEIiwgIkMxOiBBbmRhcMOpIEluc3RpdHV0ZSIgPSAiVDEzOiBBbmRhcMOpIEluc3RpdHV0ZSIsICJDMzogV09NRVIiID0gIlQ1OiBXT01FUiIsICJBNTogRG9uYXRlIFdhdGVyIFByb2plY3QiID0gIlQ5OiBEb25hdGVXYXRlciIsICJCNTogUmlnaHRzIG9mIENsaW1hdGUiID0gIlQxMTogUmlnaHRzIG9mIENsaW1hdGUiLCAiQjM6IEVjbyBXaW5uZXJzIiA9ICJUMTQ6IEVjbyBXaW5uZXJzIiwgIkI0OiBXb21lbiA0IFN1c3RhaW5hYmxlIFdvcmxkIiA9ICJUMTI6IFdvbWVuIDQgU3VzdGFpbmFibGUgV29ybGQiLCAiQTE6IFVwIEdldCBBcHAvQ2l0aUNFUk4iID0gIlQ3OiBVcEdldCBhcHAgLSBDaXRpQ0VSTiBQcm9qZWN0IiwgIkIxOiBXYXRlciBXYXJyaW9ycyIgPSAiVDEwOiBXYXRlciBXYXJyaW9ycyIsICJDMjogUEFNIiA9ICJUNDogUEFNIiwgIkM0OiBDbGltYXRlIEdlbmRlciBKdXN0aWNlIiA9ICJUODogQ2xpbWF0ZSBHZW5kZXIgSnVzdGljZSIsICJBMzogUmh5dGhtIG9mIEJhbWJvb3MiID0gIlQxOiBTRGVzaUduIChPbGQgbmFtZTogUmh5dGhtIG9mIEJhbWJvb3MpIiwgIkM1OiBBc2hpZmEgTmF6cmluIiA9ICJDNTogQXNoaWZhIE5henJpbiIsICJBNDogRmxvb2QgUmFuZ2VycyIgPSAiVDI6IEZsb29kIFJhbmdlcnMiKQoKcmVnX21hcCA9IGRhdGEuZnJhbWUob2xkX25hbWUgPSBuYW1lcyhyZWdfbWFwKSwgbmV3X25hbWUgPSByZWdfbWFwKQpyZWcgPSBtZXJnZShyZWcsIHJlZ19tYXAsIGJ5LnggPSAiVGVhbSIsIGJ5LnkgPSAib2xkX25hbWUiLCBhbGwueCA9IFRSVUUpCgp3cml0ZS5jc3YodW5uZXN0KHJlZywgY29scyA9IGMoImNvbW11bmljYXRpb24iKSksIGZpbGUgPSAiLi4vcHJvY2Vzc2VkIGRhdGEvcmVnX2VkaXRlZC5jc3YiKQoKbWFwID0gbWVyZ2UobWFwLCByZWdfbWFwLCBieS54ID0gIlRlYW0iLCBieS55ID0gIm9sZF9uYW1lIiwgYWxsLnggPSBUUlVFKQptYXAkbmV3X25hbWUgPSBhcy5jaGFyYWN0ZXIobWFwJG5ld19uYW1lKQptYXAkbmV3X25hbWVbbWFwJFRlYW0gPT0gIk9yZ2FuaXppbmcgVGVhbSJdID0gIk9yZ2FuaXppbmcgVGVhbSIKCmBgYAoKT3V0Y29tZSBWYXJpYWJsZQoKMS4gT3V0Y29tZSBlbmQgb2YgRXZhbHVhdGUKCmBgYHtyfQoKb3V0Y29tZSA9IGFzc2VzbWVudFssYygiVGVhbSIsICJUb3RhbCIsICJXZWVrbHkgRXZhbHVhdGlvbiIsICJDb21taXRtZW50IiwgIkF0dGVuZGFuY2UiLCAiRGVsaXZlcmFibGVzIildCm91dGNvbWUgPSBtZXJnZShvdXRjb21lLCB0ZWFtc1ssYygiVGVhbSBOYW1lIiwgIlN0YWdlIildLCBieS54ID0gIlRlYW0iLCBieS55ID0gIlRlYW0gTmFtZSIsIGFsbC54ID0gVFJVRSkKb3V0Y29tZSRTdGFnZSA9IGZhY3RvcihvdXRjb21lJFN0YWdlLCBsZXZlbHMgPSBjKCJFdmFsdWF0ZSIsICJBY2NlbGVyYXRlIiwgIlJlZmluZSIpLCBvcmRlcmVkID0gVFJVRSkKCmBgYAoKCjIuIFN1cnZleXMgYW5kIEludGVyYWN0aW9ucwoKYGBge3J9Cgpsb2FkKCIuLi8uLi9FdmFsdWF0ZS9wcm9jZXNzZWQgZGF0YS9zdXJ2ZXlzLlJEYXRhIikKCmludGVyID0gaW50ZXJhY3Rpb25zWyxjKDEsOCwyLDMpXQppbnRlciA9IG1lcmdlKGludGVyLCBtYXBbLGMoIklEIiwgIm5ld19uYW1lIildLCBieS54ID0gInVzZXJfaWQiLCBieS55ID0gIklEIiwgYWxsLnggPSBUUlVFKQpjb2xuYW1lcyhpbnRlcikgPSBjKCJGcm9tIiwgIlRvIiwgIlN1cnZleV9pZCIsICJRdWVzdGlvbiIsICJGcm9tX3RlYW0iKQppbnRlciA9IG1lcmdlKGludGVyLCBtYXBbLGMoIklEIiwgIm5ld19uYW1lIildLCBieS54ID0gIlRvIiwgYnkueSA9ICJJRCIsIGFsbC54ID0gVFJVRSkKY29sbmFtZXMoaW50ZXIpW2NvbG5hbWVzKGludGVyKSA9PSAibmV3X25hbWUiXSA9ICJUb190ZWFtIgoKaW50ZXIgPSBpbnRlclshaW50ZXIkVG8gJWluJSBjKDM0KSwgYygyLDEsMyw0LDUsNildCgpnX2ludF90ZWFtcyA9IGdyYXBoX2Zyb21fZGF0YV9mcmFtZShpbnRlclssYyg1LDYsMTo0KV0sIGRpcmVjdGVkID0gVFJVRSwgdmVydGljZXMgPSB0ZWFtcykKRShnX2ludF90ZWFtcykkd2VpZ2h0ID0gMQpnX2ludF90ZWFtc19zaW1wID0gc2ltcGxpZnkoZ19pbnRfdGVhbXMsIHJlbW92ZS5sb29wcyA9IEZBTFNFKQoKCmBgYAoKCjMuIENyZWF0ZSBhbiBFeHRlbnNpdmUgZGF0YWZyYW1lIHdpdGggZGlmZmVyZW50IHRoaW5ncyB0aGF0IGNhbiBiZSBjYWxjdWxhdGVkIHdpdGggdGhlIEludGVyYWN0aW9uIGRhdGEKCkxpc3RpbmcgdGhlbSBvdXQgaGVyZSAoYnkgVGVhbSkKCjEuICMgb2YgcmVzcG9uc2VzCjIuIGluLWRlZ3JlZSAoc2VsZiwgZnJvbSBvdGhlciB0ZWFtcykgKyBub3JtYWxpc2VkIChwcm9wb3J0aW9uIG9mIGluIGVkZ2VzIHRvIHNlbGYvb3RoZXJzIGV0Yy4pCjIuIG91dC1kZWdyZWUgKG9yZyB0ZWFtLCBvdGhlciB0ZWFtcykgKyBub3JtYWxpc2VkCjMuIC4uLgoKCmBgYHtyfQoKaW50ZXJfcHIgPSBpbnRlciAlPiUgZ3JvdXBfYnkoRnJvbV90ZWFtLCBUb190ZWFtKSAlPiUgc3VtbWFyaXNlKHdlaWdodCA9IG4oKSkKCiMgUmVzcG9uc2VzLCBPdXQgZGVncmVlIHRvIE9yZyBUZWFtLCBPdGhlciBwZWVycywgU2VsZgoKdGVtcCA9IGludGVyX3ByICU+JSBncm91cF9ieShGcm9tX3RlYW0pICU+JSBzdW1tYXJpc2Uobm9fcmVzcG9uc2VzID0gbigpLCBzZWxmX2ludGVyYWN0aW9ucyA9IHdlaWdodFtUb190ZWFtID09IEZyb21fdGVhbV0sIG9yZ19pbnRlcmFjdGlvbnMgPSB3ZWlnaHRbVG9fdGVhbSA9PSAiT3JnYW5pemluZyBUZWFtIl0sIHBlZXJzX291dCA9IHN1bSh3ZWlnaHRbIVRvX3RlYW0gJWluJSBjKEZyb21fdGVhbSwgIk9yZ2FuaXppbmcgVGVhbSIpXSkpCgpzdGF0cyA9IHRlbXAKCiMgSW4tZGVncmVlIGZyb20gb3RoZXIgcGVlcnMKCnRlbXAgPSBpbnRlcl9wciAlPiUgZ3JvdXBfYnkoVG9fdGVhbSkgJT4lIHN1bW1hcmlzZShwZWVyc19pbiA9IHN1bSh3ZWlnaHRbIUZyb21fdGVhbSAlaW4lIGMoVG9fdGVhbSwgIk9yZ2FuaXppbmcgVGVhbSIpXSkpCnN0YXRzID0gbWVyZ2Uoc3RhdHMsIHRlbXAsIGJ5LnggPSAiRnJvbV90ZWFtIiwgYnkueSA9ICJUb190ZWFtIiwgYWxsLnggPSBUUlVFLCBhbGwueSA9IFRSVUUpCgpzdGF0cyRzZWxmX2ludGVyYWN0aW9uc19ub3JtID0gMipzdGF0cyRzZWxmX2ludGVyYWN0aW9ucy8oMipzdGF0cyRzZWxmX2ludGVyYWN0aW9ucyArIHN0YXRzJHBlZXJzX2luICsgc3RhdHMkb3JnX2ludGVyYWN0aW9ucyArIHN0YXRzJHBlZXJzX291dCkKc3RhdHMkb3JnX2ludGVyYWN0aW9uc19ub3JtID0gc3RhdHMkb3JnX2ludGVyYWN0aW9ucy8oMipzdGF0cyRzZWxmX2ludGVyYWN0aW9ucyArIHN0YXRzJHBlZXJzX2luICsgc3RhdHMkb3JnX2ludGVyYWN0aW9ucyArIHN0YXRzJHBlZXJzX291dCkKc3RhdHMkcGVlcnNfb3V0X25vcm0gPSBzdGF0cyRwZWVyc19vdXQvKDIqc3RhdHMkc2VsZl9pbnRlcmFjdGlvbnMgKyBzdGF0cyRwZWVyc19pbiArIHN0YXRzJG9yZ19pbnRlcmFjdGlvbnMgKyBzdGF0cyRwZWVyc19vdXQpCnN0YXRzJHBlZXJzX2luX25vcm0gPSBzdGF0cyRwZWVyc19pbi8oMipzdGF0cyRzZWxmX2ludGVyYWN0aW9ucyArIHN0YXRzJHBlZXJzX2luICsgc3RhdHMkb3JnX2ludGVyYWN0aW9ucyArIHN0YXRzJHBlZXJzX291dCkKCnN0YXRzID0gc3RhdHNbIXN0YXRzJEZyb21fdGVhbSAlaW4lIGMoIk9yZ2FuaXppbmcgVGVhbSIpLF0KCmBgYAoKClNsYWNrIEludGVyYWN0aW9ucwoKYGBge3J9Cgpsb2FkKCIuLi8uLi9FdmFsdWF0ZS9wcm9jZXNzZWQgZGF0YS9zbGFja19hbGxfaW50LlJEYXRhIikKCmludGVyX3NsID0gZGZfdG90YWwgJT4lIGdyb3VwX2J5KEZyb21fVGVhbSwgVG9fVGVhbSkgJT4lIHN1bW1hcmlzZSh3ZWlnaHQgPSBuKCkpCmNvbG5hbWVzKGludGVyX3NsKSA9IGMoIkZyb21fdGVhbSIsICJUb190ZWFtIiwgIndlaWdodCIpCgp0ZW1wXzEgPSBpbnRlcl9zbCAlPiUgZ3JvdXBfYnkoRnJvbV90ZWFtKSAlPiUgc3VtbWFyaXNlKHNsYWNrX3NlbGZfaW50ZXJhY3Rpb25zID0gd2VpZ2h0W1RvX3RlYW0gPT0gRnJvbV90ZWFtXSwgc2xhY2tfb3JnX291dCA9IHdlaWdodFtUb190ZWFtID09ICJPcmdhbml6aW5nIFRlYW0iXSwgc2xhY2tfcGVlcnNfb3V0ID0gc3VtKHdlaWdodFshVG9fdGVhbSAlaW4lIGMoRnJvbV90ZWFtLCAiT3JnYW5pemluZyBUZWFtIildKSkKCnRlbXBfMiA9IGludGVyX3NsICU+JSBncm91cF9ieShUb190ZWFtKSAlPiUgc3VtbWFyaXNlKHNsYWNrX3BlZXJzX2luID0gc3VtKHdlaWdodFshRnJvbV90ZWFtICVpbiUgYyhUb190ZWFtLCAiT3JnYW5pemluZyBUZWFtIildKSwgc2xhY2tfb3JnX2luID0gd2VpZ2h0W0Zyb21fdGVhbSA9PSAiT3JnYW5pemluZyBUZWFtIl0pCgpzbGFja19zdGF0cyA9IG1lcmdlKHRlbXBfMSwgdGVtcF8yLCBieS54ID0gIkZyb21fdGVhbSIsIGJ5LnkgPSAiVG9fdGVhbSIsIGFsbC54ID0gVFJVRSwgYWxsLnkgPSBUUlVFKQpzbGFja19zdGF0cyA9IHNsYWNrX3N0YXRzWyFzbGFja19zdGF0cyRGcm9tX3RlYW0gJWluJSBjKCJPcmdhbml6aW5nIFRlYW0iLCAiVG9vbCBPd25lciIpLF0KCnNsYWNrX3N0YXRzID0gbWVyZ2Uoc2xhY2tfc3RhdHMsIHJlZ19tYXAsIGJ5LnggPSAiRnJvbV90ZWFtIiwgYnkueSA9ICJvbGRfbmFtZSIsIGFsbC54ID0gVFJVRSkKc2xhY2tfc3RhdHMkRnJvbV90ZWFtID0gc2xhY2tfc3RhdHMkbmV3X25hbWUKc2xhY2tfc3RhdHMgPSBzbGFja19zdGF0cyAlPiUgc2VsZWN0KC1uZXdfbmFtZSkKc2xhY2tfc3RhdHNbaXMubmEoc2xhY2tfc3RhdHMpXSA9IDAKCgpzbGFja19zdGF0cyRzbGFja19zZWxmX2ludGVyYWN0aW9uc19ub3JtID0gMipzbGFja19zdGF0cyRzbGFja19zZWxmX2ludGVyYWN0aW9ucy8oMipzbGFja19zdGF0cyRzbGFja19zZWxmX2ludGVyYWN0aW9ucyArIHNsYWNrX3N0YXRzJHNsYWNrX29yZ19vdXQgKyBzbGFja19zdGF0cyRzbGFja19wZWVyc19vdXQgKyBzbGFja19zdGF0cyRzbGFja19wZWVyc19pbiArIHNsYWNrX3N0YXRzJHNsYWNrX29yZ19pbikKCnNsYWNrX3N0YXRzJHNsYWNrX29yZ19vdXRfbm9ybSA9IHNsYWNrX3N0YXRzJHNsYWNrX29yZ19vdXQvKDIqc2xhY2tfc3RhdHMkc2xhY2tfc2VsZl9pbnRlcmFjdGlvbnMgKyBzbGFja19zdGF0cyRzbGFja19vcmdfb3V0ICsgc2xhY2tfc3RhdHMkc2xhY2tfcGVlcnNfb3V0ICsgc2xhY2tfc3RhdHMkc2xhY2tfcGVlcnNfaW4gKyBzbGFja19zdGF0cyRzbGFja19vcmdfaW4pCnNsYWNrX3N0YXRzJHNsYWNrX3BlZXJzX291dF9ub3JtID0gc2xhY2tfc3RhdHMkc2xhY2tfcGVlcnNfb3V0LygyKnNsYWNrX3N0YXRzJHNsYWNrX3NlbGZfaW50ZXJhY3Rpb25zICsgc2xhY2tfc3RhdHMkc2xhY2tfb3JnX291dCArIHNsYWNrX3N0YXRzJHNsYWNrX3BlZXJzX291dCArIHNsYWNrX3N0YXRzJHNsYWNrX3BlZXJzX2luICsgc2xhY2tfc3RhdHMkc2xhY2tfb3JnX2luKQpzbGFja19zdGF0cyRzbGFja19wZWVyc19pbl9ub3JtID0gc2xhY2tfc3RhdHMkc2xhY2tfcGVlcnNfaW4vKDIqc2xhY2tfc3RhdHMkc2xhY2tfc2VsZl9pbnRlcmFjdGlvbnMgKyBzbGFja19zdGF0cyRzbGFja19vcmdfb3V0ICsgc2xhY2tfc3RhdHMkc2xhY2tfcGVlcnNfb3V0ICsgc2xhY2tfc3RhdHMkc2xhY2tfcGVlcnNfaW4gKyBzbGFja19zdGF0cyRzbGFja19vcmdfaW4pCnNsYWNrX3N0YXRzJHNsYWNrX29yZ19pbl9ub3JtID0gc2xhY2tfc3RhdHMkc2xhY2tfb3JnX2luLygyKnNsYWNrX3N0YXRzJHNsYWNrX3NlbGZfaW50ZXJhY3Rpb25zICsgc2xhY2tfc3RhdHMkc2xhY2tfb3JnX291dCArIHNsYWNrX3N0YXRzJHNsYWNrX3BlZXJzX291dCArIHNsYWNrX3N0YXRzJHNsYWNrX3BlZXJzX2luICsgc2xhY2tfc3RhdHMkc2xhY2tfb3JnX2luKQoKCmBgYAoKTWVyZ2UKCmBgYHtyfQoKaW50ZXJhY3Rpb25fc3RhdHMgPSBtZXJnZShzdGF0cywgc2xhY2tfc3RhdHMsIGJ5LnggPSAiRnJvbV90ZWFtIiwgYnkueSA9ICJGcm9tX3RlYW0iLCBhbGwueCA9IFRSVUUsIGFsbC55ID0gVFJVRSkKCmBgYAoKCk5ldHdvcmsgUHJvcGVydGllcwoKYGBge3J9CgpuZXR3b3JrX3N0YXRzID0gZGF0YS5mcmFtZShub2RlcyA9IFYoZ19pbnRfdGVhbXNfc2ltcCkkbmFtZSwgc3RyZW5ndGhfaW4gPSBzdHJlbmd0aChnX2ludF90ZWFtc19zaW1wLCBtb2RlID0gImluIiksIHN0cmVuZ3RoX291dCA9IHN0cmVuZ3RoKGdfaW50X3RlYW1zX3NpbXAsIG1vZGUgPSAib3V0IiksIGJldHdlZW5uZXNzID0gYmV0d2Vlbm5lc3MoZ19pbnRfdGVhbXNfc2ltcCwgd2VpZ2h0cyA9IDEvRShnX2ludF90ZWFtc19zaW1wKSR3ZWlnaHQsIG5vcm1hbGl6ZWQgPSBUUlVFKSwgYnVydCA9IGNvbnN0cmFpbnQoZ19pbnRfdGVhbXNfc2ltcCwgd2VpZ2h0cyA9IEUoZ19pbnRfdGVhbXNfc2ltcCkkd2VpZ2h0KSkKCmBgYAoKCgoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKCjMuIFRoaW5raW5nIGFib3V0IE1ldHJpY3MKCmEuIERlc2NyaXB0aXZlCiAgaSkgR2VuZGVyIERpdmVyc2l0eQogIGlpKSBBc3NlbWJsZWQvU2VsZiBvcmdhbmlzZWQKICBpaWkpIEJhY2tncm91bmQKICBpdikgU0RHIGV4cGVyaWVuY2UKICB2KSAKICAKYi4gSW50ZXJhY3Rpb25zCiAgaSkgSW50ZXJhY3Rpb24gd2l0aCBPUkcKICBpaSkgSW50ZXJhY3Rpb24gd2l0aCBUZWFtIG1lbWJlcnMKICBpaWkpIEludGVyYWN0aW9uIHdpdGggb3RoZXIgdGVhbXMKICAKYy4gVGFza3MKCioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKCmEpIFByb2Nlc3NpbmcgUmVnLiBmaWxlIHRvIG1ha2UgdGVhbXdpc2UgZGl2ZXJzaXR5IG1ldHJpY3MKCkVudHJvcHkgLSBsb3cgc2NvcmUgZm9yIGxlc3MgZGl2ZXJzaXR5IChIaWdoZXIgZm9yIG1vcmUgZGl2ZXJzaXR5KQoKYGBge3J9CgpzaGFubm9uID0gZnVuY3Rpb24obGlzdCkKewogIGVudCA9IDAKICBmb3IgKGkgaW4gdW5pcXVlKGxpc3QpKQogIHsKICAgIHQgPSBzdW0obGlzdCA9PSBpKQogICAgbiA9IGxlbmd0aChsaXN0KQogICAgZW50ID0gZW50ICsgKHQvbikqbG9nKHQvbikKICB9CiAgCiAgcmV0dXJuKC0xKmVudCkKfQoKc2ltcHNvbiA9IGZ1bmN0aW9uKGxpc3QpCnsKICBlbnQgPSAwCiAgZm9yIChpIGluIHVuaXF1ZShsaXN0KSkKICB7CiAgICB0ID0gc3VtKGxpc3QgPT0gaSkKICAgIG4gPSBsZW5ndGgobGlzdCkKICAgIGVudCA9IGVudCArICh0L24pKih0L24pCiAgfQogIAogIHJldHVybigxL2VudCkKfQoKYGBgCgoKYGBge3J9CgptZXRyaWNzID0gZGF0YS5mcmFtZShUZWFtID0gdW5pcXVlKHJlZyRuZXdfbmFtZSkpCgpmb3IgKGkgaW4gYygiZ2VuZGVyIiwgImNvdW50cnlfb3JpZyIsICJjb3VudHJ5X3Jlc2lkIiwgImVkdWNhdGlvbiIsICJjb21tdW5pY2F0aW9uIiwgImV4YW50ZV9wcm9qZWN0X1NERyIsICJiYWNrZ3JvdW5kIiwgIm9jY3VwYXRpb24iKSkKewogIHRlbXAgPSByZWdbLGMoIm5ld19uYW1lIiwgaSldCiAgdGVtcCA9IGNsZWFuX3NwbGl0X21jcSh0ZW1wKQogIGNvbG5hbWVzKHRlbXApID0gYygiVGVhbSIsICJ2YXIiKQogIAojICBudW0gPSB0ZW1wJHZhcgogIAogIHQgPSB0ZW1wICU+JSBncm91cF9ieShUZWFtKSAlPiUgc3VtbWFyaXNlKHNoYW5ub24gPSBzaGFubm9uKHZhciksIHNpbXBzb24gPSBzaW1wc29uKHZhcikpCiAgY29sbmFtZXModCkgPSBjKCJUZWFtIiwgcGFzdGUoaSwgIl9zaGFubm9uIiwgc2VwID0gJycpLCBwYXN0ZShpLCAiX3NpbXBzb24iLCBzZXAgPSAnJykpCiAgCiAgbWV0cmljcyA9IG1lcmdlKG1ldHJpY3MsIHQsIGJ5LnggPSAiVGVhbSIsIGJ5LnkgPSAiVGVhbSIsIGFsbC54ID0gVFJVRSwgYWxsLnkgPSBUUlVFKQogIAp9CgptZXRyaWNzID0gbWVyZ2UobWV0cmljcywgdGVhbXMsIGJ5LnggPSAiVGVhbSIsIGJ5LnkgPSAiVGVhbSBOYW1lIiwgYWxsLnggPSBUUlVFKQoKbWV0cmljc19zY29yZSA9IG1lcmdlKG1ldHJpY3MsIGFzc2VzbWVudCwgYnkueCA9ICJUZWFtIiwgYnkueSA9ICJUZWFtIiwgYWxsLnggPSBUUlVFLCBhbGwueSA9IFRSVUUpCgpgYGAKCmBgYHtyfQoKbGlicmFyeShjb3JycGxvdCkKCiNtZXRyaWNzX3Njb3JlJGBGaW5hbCBQaXRjaGAgPSBhcy5udW1lcmljKG1ldHJpY3Nfc2NvcmUkYEZpbmFsIFBpdGNoYCkKI00gPSBjb3IobWV0cmljc19zY29yZVssYygyLDQsNiw4LDEwLDE0LDE2LDE5LDIxLDI0OjI3LDMxKV0sIHVzZSA9ICJjb21wbGV0ZS5vYnMiKQojY29ycnBsb3QoTSwgbWV0aG9kID0gJ251bWJlcicpICMgY29sb3JmdWwgbnVtYmVyCgp0ZW1wID0gbWVyZ2UoaW50ZXJhY3Rpb25fc3RhdHMsIG91dGNvbWUsIGJ5LnggPSAiRnJvbV90ZWFtIiwgYnkueSA9ICJUZWFtIiwgYWxsLnggPSBUUlVFLCBhbGwueSA9IFRSVUUpCk0gPSBjb3IodGVtcFssYygyOihuY29sKHRlbXApLTEpKV0sIHVzZSA9ICJjb21wbGV0ZS5vYnMiKQpjb3JycGxvdChNLCBtZXRob2QgPSAibnVtYmVyIikKYGBgCgpDbGVhbmVyIFZlcnNpb24KCmBgYHtyfQoKI291dGNvbWUgPSBjKCJGaW5hbCBQaXRjaCIsICJBcHByb3ByaWF0ZW5lc3Mgb2YgTWV0aG9kb2xvZ3kiLCAiV2Vla2x5IEV2YWx1YXRpb24iLCAiQ29tbWl0bWVudCIsICJBdHRlbmRhbmNlIiwgIkRlbGl2ZXJhYmxlcyIsICJTdW0iLCAiVG90YWwiKQoKZGZfY29yciA9IGRhdGEuZnJhbWUoKQoKZm9yIChpIGluIGNvbG5hbWVzKG91dGNvbWUpKQp7CiAgaWYoISBpICVpbiUgYygiVGVhbSIsICJTdGFnZSIpKQogIHsKICAgIGZvciAoaiBpbiBjb2xuYW1lcyhpbnRlcmFjdGlvbl9zdGF0cykpCiAgICB7CiAgICAgIGlmKCFqICVpbiUgYygiRnJvbV90ZWFtIiwgIm5vX3Jlc3BvbnNlcyIpKQogICAgICB7CiAgICAgICAgYyA9IGNvci50ZXN0KHRlbXBbLGpdLCB0ZW1wWyxpXSkKICAgICAgICAKICAgICAgICBkZl9jb3JyID0gcmJpbmQoZGZfY29yciwgZGF0YS5mcmFtZShpID0gaSwgaiA9IGosIGNvciA9IGMkZXN0aW1hdGUsIHBfdmFsID0gYyRwLnZhbHVlKSkKICAgICAgICAKICAgICAgfQogICAgfQogIH0KfQoKYGBgCgpgYGB7cn0KCmRmX2NvcnIkY29yW2RmX2NvcnIkcF92YWwgPiAwLjFdID0gMApkZl9jb3JyJGNvciA9IHJvdW5kKGRmX2NvcnIkY29yLCAzKQoKcGx0ID0gZ2dwbG90KGRmX2NvcnIpICsgZ2VvbV90aWxlKGFlcyh4ID0gaSwgeSA9IGosIGZpbGwgPSBjb3IpLCBsd2QgPSAxLjUsIGxpbmV0eXBlID0gMSkgKyBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAiYmx1ZSIsIGhpZ2ggPSAicmVkIikgKyB0aGVtZV9idygpICsgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkgKyB5bGFiKCIiKSArIHhsYWIoIiIpICsgZ2VvbV90ZXh0KGFlcyh4ID0gaSwgeSA9IGosIGxhYmVsID0gY29yKSkKCmdncGxvdGx5KHBsdCkKCmBgYApOZXR3b3JrIFByb3BzCgpgYGB7cn0KCnRlbXAgPSBtZXJnZShhc3Nlc21lbnQsIG5ldHdvcmtfc3RhdHMsIGJ5LnggPSAiVGVhbSIsIGJ5LnkgPSAibm9kZXMiLCBhbGwueCA9IFRSVUUsIGFsbC55ID0gVFJVRSkKdGVtcCA9IHRlbXBbIXRlbXAkVGVhbSA9PSAiT3JnYW5pemluZyBUZWFtIixdCgojb3V0Y29tZSA9IGMoIkZpbmFsIFBpdGNoIiwgIkFwcHJvcHJpYXRlbmVzcyBvZiBNZXRob2RvbG9neSIsICJXZWVrbHkgRXZhbHVhdGlvbiIsICJDb21taXRtZW50IiwgIkF0dGVuZGFuY2UiLCAiRGVsaXZlcmFibGVzIiwgIlN1bSIsICJUb3RhbCIpCgpkZl9jb3JyID0gZGF0YS5mcmFtZSgpCgpmb3IgKGkgaW4gY29sbmFtZXMob3V0Y29tZSkpCnsKICBpZighIGkgJWluJSBjKCJUZWFtIiwgIlN0YWdlIikpCiAgewogICAgZm9yIChqIGluIGNvbG5hbWVzKG5ldHdvcmtfc3RhdHMpKQogICAgewogICAgICBpZighaiAlaW4lIGMoIm5vZGVzIikpCiAgICAgIHsKICAgICAgICBjID0gY29yLnRlc3QodGVtcFssal0sIHRlbXBbLGldKQogICAgICAgIAogICAgICAgIGRmX2NvcnIgPSByYmluZChkZl9jb3JyLCBkYXRhLmZyYW1lKGkgPSBpLCBqID0gaiwgY29yID0gYyRlc3RpbWF0ZSwgcF92YWwgPSBjJHAudmFsdWUpKQogICAgICAgIAogICAgICB9CiAgICB9CiAgfQp9CgoKZGZfY29yciRjb3JbZGZfY29yciRwX3ZhbCA+IDAuMV0gPSAwCmRmX2NvcnIkY29yID0gcm91bmQoZGZfY29yciRjb3IsIDMpCgpwbHQgPSBnZ3Bsb3QoZGZfY29ycikgKyBnZW9tX3RpbGUoYWVzKHggPSBpLCB5ID0gaiwgZmlsbCA9IGNvciksIGx3ZCA9IDEuNSwgbGluZXR5cGUgPSAxKSArIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICJibHVlIiwgaGlnaCA9ICJyZWQiKSArIHRoZW1lX2J3KCkgKyB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpKSArIHlsYWIoIiIpICsgeGxhYigiIikgKyBnZW9tX3RleHQoYWVzKHggPSBpLCB5ID0gaiwgbGFiZWwgPSBjb3IpKQoKZ2dwbG90bHkocGx0KQpgYGAKCkRpdmVyc2l0eQoKYGBge3J9Cgp0ZW1wID0gbWVyZ2UobWV0cmljc1ssYygxOjE3KV0sIG91dGNvbWUsIGJ5LnggPSAiVGVhbSIsIGJ5LnkgPSAiVGVhbSIpCmRmX2NvcnIgPSBkYXRhLmZyYW1lKCkKCmZvciAoaSBpbiBjb2xuYW1lcyhvdXRjb21lKSkKewogIGlmKCEgaSAlaW4lIGMoIlRlYW0iLCAiU3RhZ2UiKSkKICB7CiAgICBmb3IgKGogaW4gY29sbmFtZXMobWV0cmljcykpCiAgICB7CiAgICAgIGlmKCFqICVpbiUgYygiVGVhbSIsICJUeXBlIiwgIlN0YWdlIikpCiAgICAgIHsKICAgICAgICBjID0gY29yLnRlc3QodGVtcFssal0sIHRlbXBbLGldKQogICAgICAgIAogICAgICAgIGRmX2NvcnIgPSByYmluZChkZl9jb3JyLCBkYXRhLmZyYW1lKGkgPSBpLCBqID0gaiwgY29yID0gYyRlc3RpbWF0ZSwgcF92YWwgPSBjJHAudmFsdWUpKQogICAgICAgIAogICAgICB9CiAgICB9CiAgfQp9CgpkZl9jb3JyJGNvcltkZl9jb3JyJHBfdmFsID4gMC4xXSA9IDAKZGZfY29yciRjb3IgPSByb3VuZChkZl9jb3JyJGNvciwgMykKCnBsdCA9IGdncGxvdChkZl9jb3JyKSArIGdlb21fdGlsZShhZXMoeCA9IGksIHkgPSBqLCBmaWxsID0gY29yKSwgbHdkID0gMS41LCBsaW5ldHlwZSA9IDEpICsgc2NhbGVfZmlsbF9ncmFkaWVudDIobG93ID0gImJsdWUiLCBoaWdoID0gInJlZCIpICsgdGhlbWVfYncoKSArIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpICsgeWxhYigiIikgKyB4bGFiKCIiKSArIGdlb21fdGV4dChhZXMoeCA9IGksIHkgPSBqLCBsYWJlbCA9IGNvcikpCgpnZ3Bsb3RseShwbHQpCgpgYGAKCgoKKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKgoKU29tZSBUZWFtd2lzZSBOZXR3b3JrIFByb3BlcnRpZXMKCmBgYHtyfQoKaW50ZXIgPSBpbnRlcmFjdGlvbnNbLGMoMSw4LDIsMyldCmludGVyID0gbWVyZ2UoaW50ZXIsIG1hcFssYygiSUQiLCAiVGVhbSIpXSwgYnkueCA9ICJ1c2VyX2lkIiwgYnkueSA9ICJJRCIsIGFsbC54ID0gVFJVRSkKY29sbmFtZXMoaW50ZXIpID0gYygiRnJvbSIsICJUbyIsICJTdXJ2ZXlfaWQiLCAiUXVlc3Rpb24iLCAiRnJvbV90ZWFtIikKaW50ZXIgPSBtZXJnZShpbnRlciwgbWFwWyxjKCJJRCIsICJUZWFtIildLCBieS54ID0gIlRvIiwgYnkueSA9ICJJRCIsIGFsbC54ID0gVFJVRSkKY29sbmFtZXMoaW50ZXIpW2NvbG5hbWVzKGludGVyKSA9PSAiVGVhbSJdID0gIlRvX3RlYW0iCgppbnRlciA9IGludGVyWyFpbnRlciRUbyAlaW4lIGMoMzQpLCBjKDIsMSwzLDQsNSw2KV0KCmdfaW50X3RlYW1zID0gZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGludGVyWyxjKDUsNiwxOjQpXSwgZGlyZWN0ZWQgPSBUUlVFKQpFKGdfaW50X3RlYW1zKSR3ZWlnaHQgPSAxCmdfaW50X3RlYW1zX3NpbXAgPSBzaW1wbGlmeShnX2ludF90ZWFtcywgcmVtb3ZlLmxvb3BzID0gRkFMU0UpCgoKYGBgCgpOZXR3b3JrIE1ldHJpY3MKCjEuIFdlaWdodGVkIGludGVyYWN0aW9ucyAoT3RoZXIgdGVhbXMsIHNlbGYsIE9SRykKMi4gTm9ybWFsaXNlZCB3ZWlnaHRlZCBpbnRlcmFjdGlvbnMgLSB0b3RhbCA9IDEKCgpgYGB7cn0KCnByb2Nlc3NfaW50ZXJhY3Rpb25zID0gZnVuY3Rpb24oaW50ZXIpCnsKICB0ZW1wID0gaW50ZXIgJT4lIGdyb3VwX2J5KEZyb21fdGVhbSwgVG9fdGVhbSkgJT4lIHN1bW1hcmlzZSh3ZWlnaHQgPSBuKCkpCiAgdGVtcF9vdXQgPSB0ZW1wICU+JSBncm91cF9ieShGcm9tX3RlYW0pICU+JSBzdW1tYXJpc2Uoc2VsZiA9IHdlaWdodFtUb190ZWFtID09IEZyb21fdGVhbV0sIG9yZ19vdXQgPSB3ZWlnaHRbVG9fdGVhbSA9PSAiT3JnYW5pemluZyBUZWFtIl0sIHBlZXJzX291dCA9IHN1bSh3ZWlnaHRbIVRvX3RlYW0gJWluJSBjKEZyb21fdGVhbSwgIk9yZ2FuaXppbmcgVGVhbSIpXSkpCgogIHRlbXBfaW4gPSB0ZW1wICU+JSBncm91cF9ieShUb190ZWFtKSAlPiUgc3VtbWFyaXNlKHBlZXJzX2luID0gc3VtKHdlaWdodFshRnJvbV90ZWFtID09IFRvX3RlYW1dKSkKCiAgZGVnciA9IG1lcmdlKHRlbXBfb3V0LCB0ZW1wX2luLCBieS54ID0gIkZyb21fdGVhbSIsIGJ5LnkgPSAiVG9fdGVhbSIsIGFsbC54ID0gVFJVRSwgYWxsLnkgPSBUUlVFKQogIGNvbG5hbWVzKGRlZ3IpW2NvbG5hbWVzKGRlZ3IpID09ICJGcm9tX3RlYW0iXSA9ICJUZWFtIgoKICBkZWdyID0gZGVnclshZGVnciRUZWFtID09ICJPcmdhbml6aW5nIFRlYW0iLF0KICByZXR1cm4oZGVncikKfQoKYGBgCgoKCmBgYHtyfQoKZGVnciA9IHByb2Nlc3NfaW50ZXJhY3Rpb25zKGludGVyKQojZGVnciA9IG1lcmdlKGRlZ3IsIHJlZ19tYXAsIGJ5LnggPSAiVGVhbSIsIGJ5LnkgPSAib2xkX25hbWUiKQoKZGVnciA9IG1lcmdlKGRlZ3IsIGFzc2VzbWVudCwgYnkueCA9ICJuZXdfbmFtZSIsIGJ5LnkgPSAiVGVhbSIsIGFsbC54ID0gVFJVRSwgYWxsLnkgPSBUUlVFKQpkZWdyX2FzID0gbWVyZ2UoZGVnciwgdGVhbXMsIGJ5LnggPSAibmV3X25hbWUiLCBieS55ID0gIlRlYW0gTmFtZSIpCgpgYGAKCgpQcmUtRm9ybWVkIHZzIEFzc2VtYmxlZAoKaSkgQWxsIEludGVyYWN0aW9ucwoKYGBge3J9CgpwZGYoIi4uL2ZpZ3VyZXMvc3RhdHNfdGVhbV90eXBlX2JveC5wZGYiKQoKZm9yIChpIGluIGNvbG5hbWVzKGRlZ3JfYXMpKQp7CiAgaWYoIWkgJWluJSBjKCJuZXdfbmFtZSIsICJUZWFtIiwgIlR5cGUiLCAiR2VvZ3JhcGhpYyBMb2NhdGlvbiIsICJHZW5kZXIgRi9NIiwgIlN0YWdlIikpCiAgewogICAgdGVtcCA9IGRlZ3JfYXNbLGMoIlR5cGUiLCBpKV0KICAgIGNvbG5hbWVzKHRlbXApID0gYygiVHlwZSIsICJ2YXIiKQogICAgI3QgPSB0ZW1wICU+JSBncm91cF9ieShUeXBlKSAlPiUgc3VtbWFyaXNlKG1lYW4gPSBtZWFuKHZhciksIHNlID0gc2UodmFyKSkKICAgIAogICAgcGx0ID0gZ2dwbG90KHRlbXAsIGFlcyh4ID0gVHlwZSwgeSA9IHZhcikpICsgZ2VvbV9ib3hwbG90KCkgKyB0aGVtZV9idyhiYXNlX3NpemUgPSAyMCkgKyB4bGFiKCIiKSArIHlsYWIoIiIpICsgZ2d0aXRsZShpKSArIGdlb21fcG9pbnQoYWVzKHggPSBUeXBlLCB5ID0gdmFyKSwgYWxwaGEgPSAwLjMpCiAgICAKICAgIHByaW50KHBsdCkKICAgIAogIH0KfQoKZGV2Lm9mZigpCgoKcGRmKCIuLi9maWd1cmVzL3N0YXRzX3RlYW1fdHlwZV9iYXIucGRmIikKCmZvciAoaSBpbiBjb2xuYW1lcyhkZWdyX2FzKSkKewogIGlmKCFpICVpbiUgYygibmV3X25hbWUiLCAiVGVhbSIsICJUeXBlIiwgIkdlb2dyYXBoaWMgTG9jYXRpb24iLCAiR2VuZGVyIEYvTSIsICJTdGFnZSIpKQogIHsKICAgIHRlbXAgPSBkZWdyX2FzWyxjKCJUeXBlIiwgaSldCiAgICBjb2xuYW1lcyh0ZW1wKSA9IGMoIlR5cGUiLCAidmFyIikKICAgIHQgPSB0ZW1wICU+JSBncm91cF9ieShUeXBlKSAlPiUgc3VtbWFyaXNlKG1lYW4gPSBtZWFuKHZhciksIHNlID0gc2UodmFyKSkKICAgIAogICAgcGx0ID0gZ2dwbG90KHQsIGFlcyh4ID0gVHlwZSwgeSA9IG1lYW4pKSArIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBtZWFuLXNlLCB5bWF4ID0gbWVhbitzZSksIHdpZHRoID0gMCkgKyB0aGVtZV9idyhiYXNlX3NpemUgPSAyMCkgKyB4bGFiKCIiKSArIHlsYWIoIiIpICsgZ2d0aXRsZShpKQogICAgCiAgICBwcmludChwbHQpCiAgICAKICB9Cn0KCmRldi5vZmYoKQpgYGAKCmlpKSBTcGVjaWZpYyBJbnRlcmFjdGlvbnMKCmBgYHtyfQoKCmZvciAoaiBpbiB1bmlxdWUoaW50ZXIkUXVlc3Rpb24pKQp7ICAKICAKICBhID0gcHJvY2Vzc19pbnRlcmFjdGlvbnMoaW50ZXJbaW50ZXIkUXVlc3Rpb24gPT0gaixdKQogIGEgPSBtZXJnZShhLCByZWdfbWFwLCBieS54ID0gIlRlYW0iLCBieS55ID0gIm9sZF9uYW1lIikKICBhID0gbWVyZ2UoYSwgdGVhbXMsIGJ5LnggPSAibmV3X25hbWUiLCBieS55ID0gIlRlYW0gTmFtZSIpCiAgCiAgcGRmKHBhc3RlKCIuLi9maWd1cmVzLyIsIGosICJfYm94LnBkZiIsIHNlcCA9ICIiKSkKICAKICBmb3IgKGkgaW4gY29sbmFtZXMoYSkpCiAgewogICAgaWYoIWkgJWluJSBjKCJuZXdfbmFtZSIsICJUZWFtIiwgIlR5cGUiLCAiU3RhZ2UiKSkKICAgIHsKICAgICAgdGVtcCA9IGFbLGMoIlR5cGUiLCBpKV0KICAgICAgY29sbmFtZXModGVtcCkgPSBjKCJUeXBlIiwgInZhciIpCiAgICAgIHBsdCA9IGdncGxvdCh0ZW1wLCBhZXMoeCA9IFR5cGUsIHkgPSB2YXIpKSArIGdlb21fYm94cGxvdCgpICsgdGhlbWVfYncoYmFzZV9zaXplID0gMjApICsgeGxhYigiIikgKyB5bGFiKCIiKSArIGdndGl0bGUoaSkgKyBnZW9tX3BvaW50KGFlcyh4ID0gVHlwZSwgeSA9IHZhciksIGFscGhhID0gMC4zKQogICAgICAKICAgICAgcHJpbnQocGx0KQogICAgICAKICAgIH0KICB9CiAgCiAgZGV2Lm9mZigpCiAgCnBkZihwYXN0ZSgiLi4vZmlndXJlcy8iLCBqLCAiX2Jhci5wZGYiLCBzZXAgPSAiIikpCgpmb3IgKGkgaW4gY29sbmFtZXMoYSkpCnsKICBpZighaSAlaW4lIGMoIm5ld19uYW1lIiwgIlRlYW0iLCAiVHlwZSIsICJHZW9ncmFwaGljIExvY2F0aW9uIiwgIkdlbmRlciBGL00iLCAiU3RhZ2UiKSkKICB7CiAgICB0ZW1wID0gYVssYygiVHlwZSIsIGkpXQogICAgY29sbmFtZXModGVtcCkgPSBjKCJUeXBlIiwgInZhciIpCiAgICB0ID0gdGVtcCAlPiUgZ3JvdXBfYnkoVHlwZSkgJT4lIHN1bW1hcmlzZShtZWFuID0gbWVhbih2YXIpLCBzZSA9IHNlKHZhcikpCiAgICAKICAgIHBsdCA9IGdncGxvdCh0LCBhZXMoeCA9IFR5cGUsIHkgPSBtZWFuKSkgKyBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKyBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gbWVhbi1zZSwgeW1heCA9IG1lYW4rc2UpLCB3aWR0aCA9IDApICsgdGhlbWVfYncoYmFzZV9zaXplID0gMjApICsgeGxhYigiIikgKyB5bGFiKCIiKSArIGdndGl0bGUoaSkKICAgIAogICAgcHJpbnQocGx0KQogICAgCiAgfQp9CgpkZXYub2ZmKCkKCn0KYGBgCgoKCioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCgoKYGBge3J9CgpwZGYoIi4uL2ZpZ3VyZXMvc3RhdHNfdGVhbV9wcm9ncmVzc19ib3gucGRmIikKCmZvciAoaSBpbiBjb2xuYW1lcyhkZWdyX2FzKSkKewogIGlmKCFpICVpbiUgYygibmV3X25hbWUiLCAiVGVhbSIsICJUeXBlIiwgIkdlb2dyYXBoaWMgTG9jYXRpb24iLCAiR2VuZGVyIEYvTSIsICJTdGFnZSIpKQogIHsKICAgIHRlbXAgPSBkZWdyX2FzWyxjKCJTdGFnZSIsIGkpXQogICAgY29sbmFtZXModGVtcCkgPSBjKCJUeXBlIiwgInZhciIpCiAgICAjdCA9IHRlbXAgJT4lIGdyb3VwX2J5KFR5cGUpICU+JSBzdW1tYXJpc2UobWVhbiA9IG1lYW4odmFyKSwgc2UgPSBzZSh2YXIpKQogICAgCiAgICBwbHQgPSBnZ3Bsb3QodGVtcCwgYWVzKHggPSBUeXBlLCB5ID0gdmFyKSkgKyBnZW9tX2JveHBsb3QoKSArIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDIwKSArIHhsYWIoIiIpICsgeWxhYigiIikgKyBnZ3RpdGxlKGkpICsgZ2VvbV9wb2ludChhZXMoeCA9IFR5cGUsIHkgPSB2YXIpLCBhbHBoYSA9IDAuMykKICAgIAogICAgcHJpbnQocGx0KQogICAgCiAgfQp9CgpkZXYub2ZmKCkKCgpwZGYoIi4uL2ZpZ3VyZXMvc3RhdHNfdGVhbV9wcm9ncmVzc19iYXIucGRmIikKCmZvciAoaSBpbiBjb2xuYW1lcyhkZWdyX2FzKSkKewogIGlmKCFpICVpbiUgYygibmV3X25hbWUiLCAiVGVhbSIsICJUeXBlIiwgIkdlb2dyYXBoaWMgTG9jYXRpb24iLCAiR2VuZGVyIEYvTSIsICJTdGFnZSIpKQogIHsKICAgIHRlbXAgPSBkZWdyX2FzWyxjKCJTdGFnZSIsIGkpXQogICAgY29sbmFtZXModGVtcCkgPSBjKCJUeXBlIiwgInZhciIpCiAgICB0ID0gdGVtcCAlPiUgZ3JvdXBfYnkoVHlwZSkgJT4lIHN1bW1hcmlzZShtZWFuID0gbWVhbih2YXIpLCBzZSA9IHNlKHZhcikpCiAgICAKICAgIHBsdCA9IGdncGxvdCh0LCBhZXMoeCA9IFR5cGUsIHkgPSBtZWFuKSkgKyBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKyBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gbWVhbi1zZSwgeW1heCA9IG1lYW4rc2UpLCB3aWR0aCA9IDApICsgdGhlbWVfYncoYmFzZV9zaXplID0gMjApICsgeGxhYigiIikgKyB5bGFiKCIiKSArIGdndGl0bGUoaSkKICAgIAogICAgcHJpbnQocGx0KQogICAgCiAgfQp9CgpkZXYub2ZmKCkKYGBgCg==